namespace Slackwise.OutlookUnreadNotifier
{
	using System;
	using Extensibility;
	using System.Runtime.InteropServices;
    using Outlook = Microsoft.Office.Interop.Outlook;
    using System.Diagnostics;
    using System.Drawing;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Threading;

	#region Read me for Add-in installation and setup information.
	// When run, the Add-in wizard prepared the registry for the Add-in.
	// At a later time, if the Add-in becomes unavailable for reasons such as:
	//   1) You moved this project to a computer other than which is was originally created on.
	//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
	//   3) Registry corruption.
	// you will need to re-register the Add-in by building the OutlookUnreadNotifierSetup project, 
	// right click the project in the Solution Explorer, then choose install.
	#endregion
	
	/// <summary>
	///   The object for implementing an Add-in.
	/// </summary>
	/// <seealso class='IDTExtensibility2' />
	[GuidAttribute("9FF85E52-7528-40A4-9A00-8EEEAB2E917D"), ProgId("OutlookUnreadNotifier.Connect")]
	public class Connect : Object, Extensibility.IDTExtensibility2
	{
        #region UNUSED VS-Generated Event Handlers
        /// <summary>
        ///		Implements the constructor for the Add-in object.
        ///		Place your initialization code within this method.
        /// </summary>
        public Connect()
        {
            // Don't use this function! It never seems to work right anyways! >:(
        }

        /// <summary>
        ///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
        ///     Receives notification that the Add-in is being unloaded.
        /// </summary>
        /// <param term='disconnectMode'>
        ///      Describes how the Add-in is being unloaded.
        /// </param>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
        {
        }

        /// <summary>
        ///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
        ///      Receives notification that the collection of Add-ins has changed.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnAddInsUpdate(ref System.Array custom)
        {
        }

        /// <summary>
        ///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
        ///      Receives notification that the host application has completed loading.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnStartupComplete(ref System.Array custom)
        {
        }
        #endregion

        #region Initalization
        // References to Outlook
        private Outlook.Application outlook;
        private Outlook.ExplorerClass explorer;
        private Outlook.NameSpace mapi;
        private Outlook.MAPIFolder inbox;
        private Outlook.Folders folders;
        private object addin;

        // Notification
        private System.ComponentModel.IContainer components;
        private NotifyIcon trayIcon;
        private ContextMenu trayMenu;
        private MenuItem configureAddin;
        private MenuItem openOutlook;
        private MenuItem clearNotice;
        private System.Windows.Forms.Timer CheckMailTimer;
        private string[] DefaultPersonalFolders;

        // CONFIG
        private Config config;

		/// <summary>
		///      Implements the OnConnection method of the IDTExtensibility2 interface.
		///      Receives notification that the Add-in is being loaded.
		/// </summary>
		/// <param term='application'>
		///      Root object of the host application.
		/// </param>
		/// <param term='connectMode'>
		///      Describes how the Add-in is being loaded.
		/// </param>
		/// <param term='addInInst'>
		///      Object representing this Add-in.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
		{
            // Initialize Outlook reference objects.
			outlook = (Outlook.Application) application;
            explorer = (Outlook.ExplorerClass) outlook.ActiveExplorer();
            addin = addInInst;
            mapi = outlook.GetNamespace("MAPI");
            inbox = mapi.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
            folders = mapi.Folders.GetFirst().Folders;
            DefaultPersonalFolders = new string[]
            {
                "Deleted Items",
                "Inbox",
                "Outbox",
                "Sent Items",
                "Calendar",
                "Contacts",
                "Journal",
                "Notes",
                "Tasks",
                "Drafts",
                "RSS Feeds",
                "Junk E-Mail"
            };

            // Initialize CONFIG
            config = new Config();

            // Initialize notification tray icon/balloon.
            components = new System.ComponentModel.Container();
            trayMenu = new ContextMenu();

            openOutlook = new MenuItem();
            openOutlook.Index = 0;
            openOutlook.Text = "&Open Outlook";
            openOutlook.Click += new System.EventHandler(openOutlook_Click);

            clearNotice = new MenuItem();
            clearNotice.Index = 1;
            clearNotice.Text = "&Clear Notice";
            clearNotice.Click += new System.EventHandler(clearNotice_Click);

            configureAddin = new MenuItem();
            configureAddin.Index = 2;
            configureAddin.Text = "Configure...";
            configureAddin.Click += new System.EventHandler(configureAddin_Click);

            trayMenu.MenuItems.AddRange(
               new MenuItem[] { openOutlook, clearNotice, configureAddin });

            trayIcon = new NotifyIcon(components);
            trayIcon.Icon = R.UnreadMail;
            trayIcon.ContextMenu = trayMenu;
            trayIcon.Text = "No Unread Mail";
            trayIcon.Visible = false;
            trayIcon.BalloonTipTitle = "Unread Mail";
            trayIcon.BalloonTipIcon = ToolTipIcon.Info;
            trayIcon.DoubleClick += new EventHandler(trayIcon_DoubleClick);
            trayIcon.BalloonTipClicked += new EventHandler(trayIcon_DoubleClick);

            // Initialize timer.
            CheckMailTimer = new System.Windows.Forms.Timer();
            CheckMailTimer.Interval = config.CheckMailTimerInterval;
            CheckMailTimer.Tick += new EventHandler(CheckMailTimer_Tick);
            CheckMailTimer.Start();

            // Catch the NewMail event so we can delay the timer.
            outlook.NewMail += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_NewMailEventHandler(NewMailEventHandler);
        }
        #endregion

        #region Cleanup
        /// <summary>
        ///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
        ///      Receives notification that the host application is being unloaded.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnBeginShutdown(ref System.Array custom)
        {
            // Stop timer, clean up everything!
            //CheckMailTimer.Enabled = false;
            //CheckMailTimer.Stop();
            //trayIcon.Visible = false;
            //outlook = null;
            //explorer = null;
        }
        #endregion

        #region Event Handlers
        public void NewMailEventHandler()
        {
            // Delay CheckMailTimer so rules can be processed.
            // Untested!!!
            CheckMailTimer.Enabled = false;
            CheckMailTimer.Stop();
            CheckMailTimer.Enabled = true;
            CheckMailTimer.Start();
        }

        void CheckMailTimer_Tick(object sender, EventArgs e)
        {
            checkUnread();
        }

        public void openOutlook_Click(object Sender, EventArgs e)
        {
            explorer.Display();
        }

        public void configureAddin_Click(object Sender, EventArgs e)
        {
            if (config.ShowDialog() == DialogResult.OK)
                readConfig();
        }

        public void clearNotice_Click(object Sender, EventArgs e)
        {
            trayIcon.Visible = false;
        }

        public void trayIcon_DoubleClick(object Sender, EventArgs e)
        {
            if (explorer.WindowState == Microsoft.Office.Interop.Outlook.OlWindowState.olMinimized)
                explorer.Display();
            else
                trayIcon.Visible = false;
        }
        #endregion

        #region Main Methods
        public void readConfig()
        {
            //NOTE: Update all values that use "config" properties, like below!
            CheckMailTimer.Interval = config.CheckMailTimerInterval;
        }

        public void checkUnread()
        {
            CheckMailTimer.Stop();

            // Used a flag to see if unread messages exist.
            trayIcon.Text = "";

            // Check for unread mail...
            if (config.CheckPersonalFolders) // Also check Personal Folders.
            {
                int unreadFolders = 0;

                foreach (Outlook.MAPIFolder folder in folders)
                    if (!Array.Exists(DefaultPersonalFolders, folder.Name.Equals))
                        unreadFolders += folder.UnReadItemCount;

                if (inbox.UnReadItemCount + unreadFolders > 0)
                {
                    trayIcon.Text = "(" + (inbox.UnReadItemCount + unreadFolders) + ") Unread Emails";
                    trayIcon.BalloonTipTitle = trayIcon.Text;
                    trayIcon.BalloonTipText = "(" + inbox.UnReadItemCount + ") Inbox\r\n"
                        + "(" + unreadFolders + ") Personal Folders";
                }
            }
            else // Only check Inbox for unread email.
            {
                if (inbox.UnReadItemCount > 0)
                {
                    trayIcon.Text = "(" + inbox.UnReadItemCount + ") Inbox";
                    trayIcon.BalloonTipTitle = "Unread Emails";
                    trayIcon.BalloonTipText = trayIcon.Text;
                }
            }

            // Display notification.
            if (trayIcon.Text != string.Empty)
            {
                if (!trayIcon.Visible)
                {
                    trayIcon.Visible = true;
                    trayIcon.ShowBalloonTip(30);
                }
            }
            else
                trayIcon.Visible = false;

            CheckMailTimer.Enabled = true;
        }
        #endregion
    }
}